package com.hmy.contract.service.contract.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmy.ccp.common.response.BasePageResponse;
import com.hmy.ccp.common.result.FeignResult;
import com.hmy.ccp.error.exception.HMYRuntimeException;
import com.hmy.ccp.starter.web.utils.UserContextUtil;
import com.hmy.contract.bo.request.contract.*;
import com.hmy.contract.bo.response.contract.*;
import com.hmy.contract.bo.response.order.OrderDetailResponse;
import com.hmy.contract.bo.response.order.OrderDeviceDetailResponse;
import com.hmy.contract.bo.response.order.OrderDeviceHistoryResponse;
import com.hmy.contract.bo.response.order.OrderTransportationDetailResponse;
import com.hmy.contract.commons.enums.ContractBusinessTypeEnum;
import com.hmy.contract.commons.enums.ContractStatusEnum;
import com.hmy.contract.commons.enums.ContractTypeEnum;
import com.hmy.contract.commons.enums.DictionaryConstant;
import com.hmy.contract.dal.mapper.AuthorizerModifyMapper;
import com.hmy.contract.dal.mapper.ContractMapper;
import com.hmy.contract.dal.mapper.SupplyContractMapper;
import com.hmy.contract.dal.po.AuthorizerModifyPo;
import com.hmy.contract.dal.po.ContractConfigPo;
import com.hmy.contract.dal.po.ContractPo;
import com.hmy.contract.dal.po.SupplyContractPo;
import com.hmy.contract.manager.order.OrderFeignClientManager;
import com.hmy.contract.manager.signature.SignatureFeignClientManager;
import com.hmy.contract.manager.uaa.DataDictionaryRpc;
import com.hmy.contract.manager.uaa.UaaFeignClientManager;
import com.hmy.contract.manager.worklfow.FlowProcessClientManager;
import com.hmy.contract.manager.worklfow.FlowTaskClientManager;
import com.hmy.contract.service.contract.IContractConfigService;
import com.hmy.contract.service.contract.IContractService;
import com.hmy.contract.service.contract.create.ContractCreateServiceFactory;
import com.hmy.contract.service.contract.create.IContractCreateService;
import com.hmy.contract.service.contract.save.feign.FeignSaveElectronicContractService;
import com.hmy.contract.service.contract.save.lease.ISaveLeaseContractService;
import com.hmy.contract.service.contract.save.lease.SaveLeaseContractServiceFactory;
import com.hmy.contract.service.dto.contract.*;
import com.hmy.contract.service.dto.save.SaveLeaseContractDto;
import com.hmy.contract.service.rdto.ContractActorDetailRdto;
import com.hmy.contract.service.rdto.ContractConfigRdto;
import com.hmy.contract.service.rdto.ContractRdto;
import com.hmy.contract.service.rdto.CreateContractRdto;
import com.hmy.infrastructure.api.bo.request.signature.GetSignTaskUrlApiRequest;
import com.hmy.infrastructure.api.bo.response.signature.GetSignTaskUrlApiResponse;
import com.hmy.order.api.bo.request.OrderListInfoAndSupplyQueryApiRequest;
import com.hmy.order.api.bo.response.OrderPrimaryAndSupplyApiResponse;
import com.hmy.order.api.common.enums.*;
import com.hmy.workflow.api.bo.request.process.StartProcessInstanceRequest;
import com.hmy.workflow.api.bo.request.task.ApprovalTaskRequest;
import com.hmy.workflow.api.bo.request.task.QueryNextActiveTaskRequest;
import com.hmy.workflow.api.bo.response.process.StartProcessInstanceResponse;
import com.hmy.workflow.api.enums.ApprovalStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 合同信息表 服务实现类
 *
 * @author seven.qi
 * @since 2023-12-02
 */
@Service
@Slf4j
public class ContractServiceImpl extends ServiceImpl<ContractMapper, ContractPo> implements IContractService {

    @Value("${saleManager.roleKey:SALE_MANAGER}")
    private String saleManagerRoleKey;

    @Value("${areaManager.roleKey:AREA_MANAGER}")
    private String areaManagerRoleKey;

    @Value("${riskMinister.roleKey:RISK_MINISTER}")
    private String riskMinisterRoleKey;

    @Value("${process.definition.id}")
    private String processDefinitionId;

    @Resource
    private UaaFeignClientManager uaaFeignClientManager;

    @Resource
    private SignatureFeignClientManager signatureFeignClientManager;

    @Resource
    private ContractMapper contractMapper;

    @Resource
    private IContractConfigService contractConfigService;

    @Resource
    private FeignSaveElectronicContractService feignSaveElectronicContractService;

    @Resource
    private FlowProcessClientManager flowProcessClientManager;

    @Resource
    private SupplyContractMapper supplyContractMapper;

    @Resource
    private OrderFeignClientManager orderFeignClientManager;

    @Resource
    private AuthorizerModifyMapper authorizerModifyMapper;
    @Resource
    private DataDictionaryRpc dataDictionaryRpc;

    @Resource
    private FlowTaskClientManager flowTaskClientManager;


    @Override
    @Transactional
    public CreateLeaseContractResponse createLeaseContract(CreateLeaseContractRequest createLeaseContractRequest) {

        SaveLeaseContractDto dto = BeanUtil.copyProperties(createLeaseContractRequest, SaveLeaseContractDto.class);
        OrderListInfoAndSupplyQueryApiRequest request = new OrderListInfoAndSupplyQueryApiRequest();
        request.setOrderIds(List.of(dto.getOrderId()));
        List<OrderPrimaryAndSupplyApiResponse> response = orderFeignClientManager.getOrdersInfoAndSupplyInfoByIds(request);
        if (CollUtil.isEmpty(response) || response.size() > 1) {
            throw new HMYRuntimeException(502000036);
        }
        OrderPrimaryAndSupplyDto orderDto = BeanUtil.copyProperties(response.get(0), OrderPrimaryAndSupplyDto.class);
        dto.setOrderInfo(orderDto);
        dto.getOrderInfo().setCreatorPhone(UserContextUtil.getCurrentUser().getPhone());
        ISaveLeaseContractService saveLeaseContractService = SaveLeaseContractServiceFactory.getInstance(dto.getType());
        saveLeaseContractService.beforeCreate(dto);
        String contractNo = saveLeaseContractService.generateContractNo(dto);
        dto.setContractNo(contractNo);
        ContractPo contractPo = saveLeaseContractService.save(dto);
        dto.setContractRdto(BeanUtil.copyProperties(contractPo, ContractRdto.class));

        saveLeaseContractService.afterCreate(dto);

        CreateLeaseContractResponse createContractResponse = new CreateLeaseContractResponse();
        createContractResponse.setContractId(contractPo.getContractId());
        return createContractResponse;
    }

    @Override
    @Transactional
    public CreateContractResponse saveContract(CreateContractRequest createContractRequest) {
        SaveContractDto dto = new SaveContractDto();
        BeanUtil.copyProperties(createContractRequest, dto);
        feignSaveElectronicContractService.beforeCreate(dto);

        ContractPo contractPo = feignSaveElectronicContractService.save(dto);

        feignSaveElectronicContractService.afterCreate(dto);

        CreateContractResponse createContractResponse = new CreateContractResponse();
        createContractResponse.setSuccess(Boolean.TRUE);
        createContractResponse.setContractNo(contractPo.getContractNo());
        createContractResponse.setContractId(contractPo.getContractId());
        return createContractResponse;
    }


    @Override
    public ContractInfoResponse contractInfo(ContractInfoRequest contractInfoRequest) {
        LambdaQueryWrapper<ContractPo> wrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotEmpty(contractInfoRequest.getContractNo())) {
            wrapper.eq(ContractPo::getContractNo, contractInfoRequest.getContractNo());
        }
        if (null != contractInfoRequest.getContractId()) {
            wrapper.eq(ContractPo::getContractId, contractInfoRequest.getContractId());
        }
        ContractPo contractPo = contractMapper.selectOne(wrapper);
        if (contractPo == null || contractPo.getIsDeleted()) {
            throw new HMYRuntimeException(502000002);
        }
        ContractInfoResponse contractInfoResponse = new ContractInfoResponse();
        BeanUtil.copyProperties(contractPo, contractInfoResponse, "orderDetailExtension", "customerExtension");
        contractInfoResponse.setContractTypeDesc(ContractTypeEnum.getDescByType(contractPo.getContractType()));
        contractInfoResponse.setStatusDesc(ContractStatusEnum.getDescByStatus(contractPo.getStatus()));
        contractInfoResponse.setLessorDetail(JSONUtil.toBean(contractPo.getLessorInfo(), LessorInfoResponse.class));
        contractInfoResponse.setProcessInstanceId(contractPo.getProcessId());
        contractInfoResponse.setContractProcessInstanceId(contractPo.getProcessId());
        contractInfoResponse.setLessorInfo(contractPo.getLessorInfo());
        contractInfoResponse.setAuthorizerInfo(contractPo.getAuthorizerInfo());
        contractInfoResponse.setOrderDetailExtension(contractPo.getOrderDetailExtension());
        contractInfoResponse.setLessorInfo(contractPo.getLessorInfo());
        if (StrUtil.isNotEmpty(contractPo.getCustomerExtension())) {
            CustomerExtensionDto customerExtensionDto = JSON.parseObject(contractPo.getCustomerExtension(), CustomerExtensionDto.class);
            contractInfoResponse.setCustomerExtension(BeanUtil.copyProperties(customerExtensionDto, CustomerExtensionResponse.class));
            contractInfoResponse.setContacterName(customerExtensionDto.getCustomerContactorName());
            contractInfoResponse.setCustomerPhone(customerExtensionDto.getCustomerContactorPhone());
            contractInfoResponse.setCustomerName(customerExtensionDto.getCustomerName());
            contractInfoResponse.setCustomerId(customerExtensionDto.getCustomerId());
            contractInfoResponse.setCustomerIdCardNo(customerExtensionDto.getCustomerContactorIdCardNumber());
        }
        // 解析contractSignTaskUrl
        if (StrUtil.isNotEmpty(contractPo.getContractSignTaskUrl())) {
            SignTaskDto signTaskDto = JSONUtil.toBean(contractPo.getContractSignTaskUrl(), SignTaskDto.class);
            contractInfoResponse.setContractSignTaskUrl(signTaskDto.getContractSignTaskUrl());
        }
        // 调用订单侧接口获取订单详情返回给前端
        OrderListInfoAndSupplyQueryApiRequest request = new OrderListInfoAndSupplyQueryApiRequest();
        request.setOrderIds(List.of(contractPo.getOrderId()));
        List<OrderPrimaryAndSupplyApiResponse> response = orderFeignClientManager.getOrdersInfoAndSupplyInfoByIds(request);
        if (CollUtil.isNotEmpty(response)) {
            OrderDetailResponse orderDetailResponse = BeanUtil.copyProperties(response.get(0), OrderDetailResponse.class);
            for (OrderDeviceDetailResponse orderDeviceDetail : orderDetailResponse.getOrderDeviceDetails()) {
                orderDeviceDetail.setDeviceTypeAlias(OrderDeviceEnum.getDescByType(orderDeviceDetail.getDeviceType()));
                orderDeviceDetail.setRentalTypeDesc(orderDeviceDetail.getRentalType() == 1 ? "日租" : "月租");
            }
            List<OrderTransportationDetailResponse> orderTransportationDetails = orderDetailResponse.getOrderTransportationDetails();
            if (CollUtil.isNotEmpty(orderTransportationDetails)) {
                orderTransportationDetails.forEach(orderTransportationDetail -> {
                    orderTransportationDetail.setTransportationAgreementDesc(OrderTransportationConstraintEnum.getDescByType(orderTransportationDetail.getTransportationAgreementType().byteValue()));
                });
            }
            List<OrderDeviceHistoryResponse> orderDeviceHistory = orderDetailResponse.getOrderDeviceHistory();
            if (CollUtil.isNotEmpty(orderDeviceHistory)) {
                orderDeviceHistory.forEach(orderDeviceHistoryResponse -> {
                    if (Boolean.FALSE.equals(orderDeviceHistoryResponse.getSupply())) {
                        orderDeviceHistoryResponse.setContractProcessInstanceId(contractPo.getProcessId());
                    } else {
                        LambdaQueryWrapper<SupplyContractPo> wrapper1 = new LambdaQueryWrapper<>();
                        wrapper1.eq(SupplyContractPo::getSupplyContractNo, orderDeviceHistoryResponse.getContractNo());
                        wrapper1.eq(SupplyContractPo::getIsDeleted, Boolean.FALSE);
                        SupplyContractPo supplyContractPo = supplyContractMapper.selectOne(wrapper1);
                        if (Objects.nonNull(supplyContractPo)) {
                            orderDeviceHistoryResponse.setContractProcessInstanceId(supplyContractPo.getProcessId());
                        }
                    }
                });
            }
            contractInfoResponse.setOrderDetail(orderDetailResponse);
        }

        // 查询最新的授权人变更信息
        getLatestAuthorizerModify(contractInfoResponse);
        return contractInfoResponse;
    }

    @Override
    public ContractInfoResponse contractInfoBySignTaskId(ContractInfoRequest contractInfoRequest) {
        LambdaQueryWrapper<ContractPo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ContractPo::getContractTaskId, contractInfoRequest.getSignTaskId());
        lambdaQueryWrapper.eq(ContractPo::getIsDeleted, Boolean.FALSE);
        ContractPo contractPo = contractMapper.selectOne(lambdaQueryWrapper);
        if (contractPo == null) {
            throw new HMYRuntimeException(502000002);
        }
        ContractInfoResponse contractInfoResponse = new ContractInfoResponse();
        BeanUtil.copyProperties(contractPo, contractInfoResponse);
        contractInfoResponse.setContractTypeDesc(ContractTypeEnum.getDescByType(contractPo.getContractType()));
        contractInfoResponse.setStatusDesc(ContractStatusEnum.getDescByStatus(contractPo.getStatus()));
        return contractInfoResponse;
    }

    @Override
    public Long contractInfoBySignTaskId(String signTaskId) {
        LambdaQueryWrapper<ContractPo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ContractPo::getContractTaskId, signTaskId);
        lambdaQueryWrapper.eq(ContractPo::getIsDeleted, Boolean.FALSE);
        ContractPo contractPo = contractMapper.selectOne(lambdaQueryWrapper);
        if (contractPo == null) {
            throw new HMYRuntimeException(502000002);
        }
        return contractPo.getContractId();
    }

    @Override
    @Transactional
    public UpdateFileUrlResponse updateFileUrl(UpdateFileUrlRequest updateFileUrlRequest) {

        ContractPo contractRo = getById(updateFileUrlRequest.getContractId());
        if (contractRo == null) {
            throw new HMYRuntimeException(502000002);
        }


        ContractPo contractPo = new ContractPo();

        if (ContractStatusEnum.REJECT.getStatus().equals(contractRo.getStatus()) && StrUtil.isNotEmpty(contractRo.getProcessId())) {
            // 驳回之后不需要重新发起流程
            QueryNextActiveTaskRequest request = new QueryNextActiveTaskRequest();
            request.setProcessInstanceId(contractRo.getProcessId());
            String nextActiveTaskId = flowTaskClientManager.queryNextActiveTask(request);
            Map<String, Object> variablesMap = new HashMap<>();
            variablesMap.put("contractType", contractRo.getContractType());
            variablesMap.put("contractTypeDesc", ContractTypeEnum.getDescByType(contractRo.getContractType()));
            variablesMap.put("businessStatus", ContractStatusEnum.WAITING_APPROVAL.getStatus());
            variablesMap.put("businessStatusAlias", ContractStatusEnum.WAITING_APPROVAL.getStatusDesc());
            variablesMap.put("rejectCount", "0");
            ApprovalTaskRequest taskRequest = new ApprovalTaskRequest();
            taskRequest.setVariables(variablesMap);
            taskRequest.setApprovalStatus(ApprovalStatusEnum.PASS.getCode());
            taskRequest.setProcessInstanceId(contractRo.getProcessId());
            taskRequest.setTaskId(nextActiveTaskId);
            taskRequest.setComment("重新提交");
            try {
                flowTaskClientManager.complete(taskRequest);
            } catch (Exception e) {
                throw new HMYRuntimeException(5010014);
            }

        } else {
            StartProcessInstanceRequest startProcessInstanceRequest = new StartProcessInstanceRequest();
            startProcessInstanceRequest.setProcessDefinitionId(processDefinitionId);
            startProcessInstanceRequest.setUserId(UserContextUtil.getCurrentUserId());
            // 业务数据转map
            Map<String, Object> variablesMap = converterToProcessVariableMap(ContractStatusEnum.WAITING_APPROVAL, contractRo);
            startProcessInstanceRequest.setProcessVariables(variablesMap);
            StartProcessInstanceResponse processInstanceResponse = flowProcessClientManager.start(startProcessInstanceRequest);
            if (Objects.isNull(processInstanceResponse) || StringUtils.isEmpty(processInstanceResponse.getProcessInstanceId())) {
                throw new HMYRuntimeException(5010014);
            }
            contractPo.setProcessId(processInstanceResponse.getProcessInstanceId());
        }

        contractPo.setContractSignFileUrl(updateFileUrlRequest.getFileUrl());
        // 上传完文件后状态为待审批
        contractPo.setStatus(ContractStatusEnum.WAITING_APPROVAL.getStatus());
        // 上传完文件后插入当前时间作为签署时间
        contractPo.setSignTime(LocalDateTime.now());
        LambdaQueryWrapper<ContractPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ContractPo::getContractId, contractRo.getContractId());
        wrapper.eq(ContractPo::getIsDeleted, Boolean.FALSE);

        update(contractPo, wrapper);

        UpdateFileUrlResponse updateFileUrlResponse = new UpdateFileUrlResponse();
        updateFileUrlResponse.setContractId(contractPo.getContractId());
        return updateFileUrlResponse;
    }

    private Map<String, Object> converterToProcessVariableMap(ContractStatusEnum contractStatusEnum, ContractPo contractRo) {
        Map<String, Object> variablesMap = BeanUtil.beanToMap(contractRo);
        variablesMap.put("contractTypeDesc", ContractTypeEnum.getDescByType(contractRo.getContractType()));
        variablesMap.put("businessStatus", contractStatusEnum.getStatus());
        variablesMap.put("businessStatusAlias", contractStatusEnum.getStatusDesc());
        variablesMap.put("rejectCount", "0");
        return variablesMap;
    }

    @Override
    public GetSignUrlResponse getSignUrl(GetSignUrlRequest getSignUrlRequest) {

        ContractPo contractPo = getById(getSignUrlRequest.getContractId());
        if (contractPo == null) {
            throw new HMYRuntimeException(502000002);
        }

        GetSignTaskUrlApiRequest getSignTaskUrlApiRequest = new GetSignTaskUrlApiRequest();
        getSignTaskUrlApiRequest.setSignTaskId(contractPo.getContractTaskId());

        FeignResult<GetSignTaskUrlApiResponse> signTaskUrl = signatureFeignClientManager.getSignTaskUrl(getSignTaskUrlApiRequest);

        GetSignUrlResponse getSignUrlResponse = new GetSignUrlResponse();
        getSignUrlResponse.setSignUrl(signTaskUrl.getData().getSignTaskUrl());
        return getSignUrlResponse;
    }

    @Override
    public BasePageResponse<ContractPageResponse> page(ContractPageRequest contractPageRequest) {
        Page<ContractPageResponse> contractPageResponsePage = new Page<>();
        Page<ContractPo> page = new Page<>(contractPageRequest.getPageNum(), contractPageRequest.getPageSize());
        LambdaQueryWrapper<ContractPo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.orderByDesc(ContractPo::getContractId);
        addQueryCondition(contractPageRequest, lambdaQueryWrapper);

        addRoleCondition(lambdaQueryWrapper);

        Page<ContractPo> contractPoPage = page(page, lambdaQueryWrapper);
        List<ContractPageResponse> response = new ArrayList<>();
        if (CollUtil.isNotEmpty(contractPoPage.getRecords())) {
            BeanUtil.copyProperties(contractPoPage, contractPageResponsePage);
            contractPageResponsePage.setRecords(BeanUtil.copyToList(contractPoPage.getRecords(), ContractPageResponse.class));
            for (ContractPo record : contractPoPage.getRecords()) {
                ContractPageResponse contractPageResponse = BeanUtil.copyProperties(record, ContractPageResponse.class);
                contractPageResponse.setContractTypeDesc(ContractTypeEnum.getDescByType(record.getContractType()));
                contractPageResponse.setStatusDesc(ContractStatusEnum.getDescByStatus(record.getStatus()));
                contractPageResponse.setProcessInstanceId(record.getProcessId());
                contractPageResponse.setContractProcessInstanceId(record.getProcessId());
                if (StrUtil.isNotEmpty(record.getContractSignTaskUrl())) {
                    SignTaskDto signTaskDto = JSONUtil.toBean(record.getContractSignTaskUrl(), SignTaskDto.class);
                    contractPageResponse.setContractSignTaskUrl(signTaskDto.getContractSignTaskUrl());
                }
                // 解析客户扩展信息
                if (StrUtil.isNotEmpty(record.getCustomerExtension())) {
                    parseCustomerExtension(record.getCustomerExtension(), contractPageResponse);
                }
                // 解析审批意见
                if (StrUtil.isNotEmpty(record.getExtendedFields())) {
                    ApprovalCommentDto approvalCommentDto = JSONUtil.toBean(record.getExtendedFields(), ApprovalCommentDto.class);
                    contractPageResponse.setApprovalComment(approvalCommentDto.getComment());
                }
                // 解析订单详情
                if (StrUtil.isNotEmpty(record.getOrderDetailExtension())) {
                    OrderListInfoAndSupplyQueryApiRequest request = new OrderListInfoAndSupplyQueryApiRequest();
                    request.setOrderIds(List.of(record.getOrderId()));
                    List<OrderPrimaryAndSupplyApiResponse> orderResponse = orderFeignClientManager.getOrdersInfoAndSupplyInfoByIds(request);
                    if (CollUtil.isEmpty(orderResponse) || orderResponse.size() > 1) {
                        throw new HMYRuntimeException(502000036);
                    }
                    OrderPrimaryAndSupplyDto bean = BeanUtil.copyProperties(orderResponse.get(0), OrderPrimaryAndSupplyDto.class);
                    bean.setPaymentPeriodDesc(bean.getPaymentPeriodType() == null ? null :
                            OrderPaymentPeriodEnum.getDescByType(bean.getPaymentPeriodType()));
                    bean.setPaymentMethodDesc(bean.getPaymentMethodType() == null ? null :
                            OrderPaymentMethodEnum.getDescByType(bean.getPaymentMethodType()));
                    contractPageResponse.setOrderDetail(BeanUtil.copyProperties(bean, OrderDetailResponse.class));
                }
                // 添加增补合同数量
                LambdaQueryWrapper<SupplyContractPo> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(SupplyContractPo::getContractNo, record.getContractNo());
                wrapper.eq(SupplyContractPo::getIsDeleted, Boolean.FALSE);
                wrapper.in(SupplyContractPo::getStatus, ContractStatusEnum.SIGNED.getStatus(), ContractStatusEnum.APPROVED.getStatus());
                Integer supplyCount = supplyContractMapper.selectCount(wrapper);
                contractPageResponse.setSupplyCount(supplyCount);
                Map<String, String> contractCssTagMap = dataDictionaryRpc.queryCssTag(DictionaryConstant.CONTRACT_STATUS);
                contractPageResponse.setContractStatusCssTag(contractCssTagMap.get(String.valueOf(contractPageResponse.getStatus())));
                response.add(contractPageResponse);
            }
        }
        BasePageResponse<ContractPageResponse> pageResponse = new BasePageResponse<>();
        pageResponse.setPages(contractPageResponsePage.getPages());
        pageResponse.setRecords(response);
        pageResponse.setSize(contractPageResponsePage.getSize());
        pageResponse.setTotal(contractPageResponsePage.getTotal());
        pageResponse.setCurrent(contractPageResponsePage.getCurrent());
        return pageResponse;
    }

    private void parseCustomerExtension(String customerExtension, ContractPageResponse contractPageResponse) {
        CustomerExtensionDto customerExtensionDto = JSONUtil.toBean(customerExtension, CustomerExtensionDto.class);
        CustomerExtensionResponse customerExtensionResponse = BeanUtil.copyProperties(customerExtensionDto, CustomerExtensionResponse.class);
        if (StrUtil.isNotEmpty(customerExtensionDto.getCustomerType())) {
            customerExtensionResponse.setCustomerTypeAlias(customerExtensionDto.getCustomerType().equals("0") ? "个人客户" : "企业客户");
        }
        contractPageResponse.setCustomerDetail(customerExtensionResponse);
    }



    @Override
    @Transactional
    public void contractCreate(Long contractId) {
        ContractPo contractRo = getById(contractId);
        if (ObjectUtil.isEmpty(contractRo)) {
            throw new HMYRuntimeException(502000002);
        }
        CreateContractRdto createContractRdto = getCreateContractRdto(contractRo);
        createContractRdto.setContractRdto(BeanUtil.copyProperties(contractRo, ContractRdto.class));
        IContractCreateService contractCreateService = ContractCreateServiceFactory.getInstance(createContractRdto.getBusinessType());

        contractCreateService.beforeCreate(createContractRdto);
        // 电子合同的signTaskId是法大大的任务id，纸质合同是存储文件模板的id
        String signTaskId = contractCreateService.create(createContractRdto);
        createContractRdto.getContractRdto().setContractTaskId(signTaskId);
        // 电子合同的url是签署地址，纸质合同的url是文件存储到oss的相对路径
        String url = contractCreateService.start(signTaskId, contractCreateService.fillFieldValue(createContractRdto), createContractRdto);
        createContractRdto.setUrl(url);

        contractCreateService.afterCreate(createContractRdto);
    }

    private CreateContractRdto getCreateContractRdto(ContractPo contractRo) {
        LambdaQueryWrapper<ContractConfigPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ContractConfigPo::getContractBusinessType, contractRo.getBusinessType());
        wrapper.eq(ContractConfigPo::getIsDeleted, Boolean.FALSE);
        ContractConfigPo contractConfigRo = contractConfigService.getOne(wrapper);
        if (ObjectUtil.isEmpty(contractConfigRo)) {
            throw new HMYRuntimeException(502000017);
        }
        ActorConfigDto config = JSONUtil.toBean(contractConfigRo.getActorConfig(), ActorConfigDto.class);
        ActorDetailExtensionDto actorDto = JSONUtil.toBean(contractRo.getActorDetailExtension(), ActorDetailExtensionDto.class);
        CreateContractRdto createContractRdto = BeanUtil.copyProperties(contractRo, CreateContractRdto.class);
        if (StrUtil.isNotEmpty(contractRo.getTemplateDataDetailExtension())) {
            createContractRdto.setFieldMap(JSONUtil.toBean(contractRo.getTemplateDataDetailExtension(), TemplateDataDetailExtensionDto.class).getFields());
        }
        createContractRdto.setSignTemplateId(contractConfigRo.getTemplateId());
        createContractRdto.setContractActorDetailList(buildContractActorDetailList(actorDto.getActorDetailList(), config.getActorDetailList()));
        createContractRdto.setBusinessId(contractConfigRo.getBusinessId());
        createContractRdto.setTaskSubject(contractRo.getContractName());
        createContractRdto.setBusinessType(contractRo.getBusinessType());
        createContractRdto.setContractConfigRdto(buildContractConfigRdto(contractConfigRo));
        return createContractRdto;
    }

    private ContractConfigRdto buildContractConfigRdto(ContractConfigPo contractConfigRo) {
        ContractConfigRdto rdto = new ContractConfigRdto();
        rdto.setContractName(contractConfigRo.getContractName());
        rdto.setBusinessId(contractConfigRo.getBusinessId());
        rdto.setTaskSubject(contractConfigRo.getContractName());
        rdto.setSealId(contractConfigRo.getSealId());
        rdto.setSignTemplateId(contractConfigRo.getTemplateId());
//        rdto.setActorConfigList(JSONUtil.toList(contractConfigRo.getActorConfig(), ContractActorDetailRdto.class));
        return rdto;
    }

    private List<ContractActorDetailRdto> buildContractActorDetailList(List<ContractActorDto> actorDto, List<ContractActorDetailRdto> config) {
        List<ContractActorDetailRdto> contractActorDetailRdtoList = new ArrayList<>();
        Map<String, List<ContractActorDetailRdto>> collect = config.stream().collect(Collectors.groupingBy(ContractActorDetailRdto::getActorId));
        actorDto.forEach(actor -> {
            ContractActorDetailRdto contractActorDetailRdto = collect.get(actor.getActorId()).get(0);
            contractActorDetailRdto.setActorName(actor.getActorName());
            contractActorDetailRdto.setNotifyAddress(actor.getActorPhone());
            contractActorDetailRdto.setAccountName(actor.getActorPhone());
            contractActorDetailRdto.setCertNoForMatch(actor.getActorIdCardNo());
            contractActorDetailRdtoList.add(contractActorDetailRdto);
        });
        return contractActorDetailRdtoList;
    }

    @Override
    public List<Long> getWaitingCreateContract(Long count) {
        LambdaQueryWrapper<ContractPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ContractPo::getStatus, ContractStatusEnum.WAITING_CREATE.getStatus());
        wrapper.eq(ContractPo::getIsDeleted, 0);
        wrapper.orderByAsc(ContractPo::getCreateTime);
        Page<ContractPo> page = new Page<>(1, count);
        Page<ContractPo> roPage = contractMapper.selectPage(page, wrapper);
        if (roPage == null || CollUtil.isEmpty(roPage.getRecords())) {
            return null;
        }
        return roPage.getRecords().stream().map(ContractPo::getContractId).collect(Collectors.toList());
    }

    @Override
    public void updateContractStatusFailed(Long contractId) {
        ContractPo contractPo = new ContractPo();
        contractPo.setStatus(ContractStatusEnum.CONTRACT_CREATE_FAILED.getStatus());
        LambdaQueryWrapper<ContractPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ContractPo::getContractId, contractId);
        wrapper.eq(ContractPo::getIsDeleted, Boolean.FALSE);
        update(contractPo, wrapper);
    }

    @Override
    public BasePageResponse<ContractQueryListResponse> pageQueryContract(ContractQueryListRequest request) {
        LambdaQueryWrapper<ContractPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(CollUtil.isNotEmpty(request.getStatusList()), ContractPo::getStatus, request.getStatusList());
        wrapper.in(CollUtil.isNotEmpty(request.getBusinessTypeList()), ContractPo::getBusinessType, request.getBusinessTypeList());
        wrapper.eq(ContractPo::getIsDeleted, 0);
        //模糊查询
        if (StringUtils.isNotBlank(request.getContractNoOrName())) {
            wrapper.and(wp -> wp.like(ContractPo::getContractNo, request.getContractNoOrName())
                    .or().like(ContractPo::getContractName, request.getContractNoOrName()));
        }
        //查询合同列表
        Page<ContractPo> page = contractMapper.selectPage(new Page<ContractPo>(request.getPageNum(), request.getPageSize()),wrapper);

        //构造出参
        BasePageResponse<ContractQueryListResponse> pageResponse = new BasePageResponse<>();
        pageResponse.setRecords(ContractQueryListResponse.convertToRsp(page.getRecords()));
        pageResponse.setTotal(page.getTotal());
        pageResponse.setPages(page.getPages());
        pageResponse.setSize(page.getSize());
        pageResponse.setCurrent(page.getCurrent());

        return pageResponse;
    }

    @Override
    public GetContractInfoByRelationIdResponse getContractInfoByRelationId(GetContractInfoByRelationIdRequest request) {
        log.info("getContractInfoByRelationId request:{}", JSONUtil.toJsonStr(request));
        GetContractInfoByRelationIdResponse response = new GetContractInfoByRelationIdResponse();
        if (request.getIsSupply()) {
            LambdaQueryWrapper<SupplyContractPo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SupplyContractPo::getRelationId, request.getRelationId());
            wrapper.eq(SupplyContractPo::getIsDeleted, Boolean.FALSE);
            SupplyContractPo supplyContractPo = supplyContractMapper.selectOne(wrapper);
            if (ObjectUtil.isNull(supplyContractPo)) {
                log.error("getContractInfoByRelationId supplyContractPo is null, request:{}", JSONUtil.toJsonStr(request));
                throw new HMYRuntimeException(502000035);
            }
            response.setContractId(supplyContractPo.getContractId());
            response.setContractNo(supplyContractPo.getSupplyContractNo());
            if (StrUtil.isNotEmpty(supplyContractPo.getContractFileUrl())) {
                response.setContractFileUrl(supplyContractPo.getContractFileUrl());
            }
            if (StrUtil.isNotEmpty(supplyContractPo.getContractSignTaskUrl())) {
                SignTaskDto signTaskDto = JSONUtil.toBean(supplyContractPo.getContractSignTaskUrl(), SignTaskDto.class);
                response.setContractSignTaskUrl(signTaskDto.getContractSignTaskUrl());
            }
            if (StrUtil.isNotEmpty(supplyContractPo.getContractSignFileUrl())) {
                response.setContractSignFileUrl(supplyContractPo.getContractSignFileUrl());
            }
        } else {
            LambdaQueryWrapper<ContractPo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ContractPo::getRelationId, request.getRelationId());
            wrapper.eq(ContractPo::getIsDeleted, Boolean.FALSE);
            ContractPo contractPo = contractMapper.selectOne(wrapper);
            if (ObjectUtil.isNull(contractPo)) {
                log.error("getContractInfoByRelationId contractPo is null, request:{}", JSONUtil.toJsonStr(request));
                throw new HMYRuntimeException(502000002);
            }
            response.setContractId(contractPo.getContractId());
            response.setContractNo(contractPo.getContractNo());
            if (StrUtil.isNotEmpty(contractPo.getContractFileUrl())) {
                response.setContractFileUrl(contractPo.getContractFileUrl());
            }
            if (StrUtil.isNotEmpty(contractPo.getContractSignTaskUrl())) {
                SignTaskDto signTaskDto = JSONUtil.toBean(contractPo.getContractSignTaskUrl(), SignTaskDto.class);
                response.setContractSignTaskUrl(signTaskDto.getContractSignTaskUrl());
            }
            if (StrUtil.isNotEmpty(contractPo.getContractSignFileUrl())) {
                response.setContractSignFileUrl(contractPo.getContractSignFileUrl());
            }
        }
        return response;
    }

    @Override
    @Transactional
    public ContractInfoResponse signFinished(ContractSignFinishedRequest contractSignFinishedRequest) {
        // 法大大回调时，根据不同的businessType获取不同的service，调用对应的回调方法
        ContractRevokeDto contractRevokeDto = new ContractRevokeDto();
        if (StrUtil.isEmpty(contractSignFinishedRequest.getTransReferenceId())) {
            LambdaQueryWrapper<ContractPo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(ContractPo::getContractTaskId, contractSignFinishedRequest.getSignTaskId());
            lambdaQueryWrapper.eq(ContractPo::getIsDeleted, Boolean.FALSE);
            ContractPo contractPo = contractMapper.selectOne(lambdaQueryWrapper);
            if (contractPo == null) {
                throw new HMYRuntimeException(502000002);
            }
            contractRevokeDto.setBusinessType(contractPo.getBusinessType());
        } else {
            contractRevokeDto.setBusinessType(Integer.parseInt(contractSignFinishedRequest.getTransReferenceId()));
        }
        contractRevokeDto.setSignTaskId(contractSignFinishedRequest.getSignTaskId());
        IContractCreateService contractCreateService = ContractCreateServiceFactory.getInstance(contractRevokeDto.getBusinessType());
        Long contractId = null;
        try {
            contractId = contractCreateService.notify(contractRevokeDto);
        } catch (Throwable throwable) {
            log.error("signFinished error", throwable);
        }
        ContractInfoResponse contractInfoResponse = new ContractInfoResponse();
        contractInfoResponse.setContractId(contractId);
        return contractInfoResponse;
    }

    private void addQueryCondition(ContractPageRequest contractPageRequest, LambdaQueryWrapper<ContractPo> lambdaQueryWrapper) {
        if (StrUtil.isNotEmpty(contractPageRequest.getContractName())) {
            lambdaQueryWrapper.like(ContractPo::getContractName, contractPageRequest.getContractName());
        }
        if (contractPageRequest.getContractType() != null) {
            lambdaQueryWrapper.eq(ContractPo::getContractType, contractPageRequest.getContractType());
        }

        if (CollUtil.isNotEmpty(contractPageRequest.getStatus())) {
            lambdaQueryWrapper.in(ContractPo::getStatus, contractPageRequest.getStatus());
        }
        if (StrUtil.isNotEmpty(contractPageRequest.getContractNo())) {
            lambdaQueryWrapper.like(ContractPo::getContractNo, contractPageRequest.getContractNo());
        }
        if (StrUtil.isNotEmpty(contractPageRequest.getOrderNo())) {
            lambdaQueryWrapper.like(ContractPo::getOrderNo, contractPageRequest.getOrderNo());
        }
        if (StrUtil.isNotEmpty(contractPageRequest.getCustomerName())) {
            lambdaQueryWrapper.like(ContractPo::getCustomerName, contractPageRequest.getCustomerName());
        }
        if (StrUtil.isNotEmpty(contractPageRequest.getProjectName())) {
            lambdaQueryWrapper.like(ContractPo::getProjectName, contractPageRequest.getProjectName());
        }
        if (StrUtil.isNotEmpty(contractPageRequest.getCreatorName())) {
            lambdaQueryWrapper.like(ContractPo::getCreatorName, contractPageRequest.getCreatorName());
        }
        if (StrUtil.isNotEmpty(contractPageRequest.getContractCreateTimeStart())) {
            lambdaQueryWrapper.ge(ContractPo::getCreateTime, contractPageRequest.getContractCreateTimeStart());
        }
        if (StrUtil.isNotEmpty(contractPageRequest.getContractCreateTimeEnd())) {
            lambdaQueryWrapper.le(ContractPo::getCreateTime, contractPageRequest.getContractCreateTimeEnd());
        }
        // 根据searchValue多条件or查询
        if (StrUtil.isNotEmpty(contractPageRequest.getSearchValue())) {
            lambdaQueryWrapper.and(wrapper -> wrapper.like(ContractPo::getContractNo, contractPageRequest.getSearchValue())
                    .or().like(ContractPo::getCustomerName, contractPageRequest.getSearchValue())
                    .or().like(ContractPo::getProjectName, contractPageRequest.getSearchValue())
            );
        }
        if (null != contractPageRequest.getHasSupply()) {
            lambdaQueryWrapper.eq(ContractPo::getHasSupply, contractPageRequest.getHasSupply());
        }

        lambdaQueryWrapper.eq(ContractPo::getIsDeleted, Boolean.FALSE);
        lambdaQueryWrapper.in(ContractPo::getBusinessType, ContractBusinessTypeEnum.SALE_ELECTRONIC_CONTRACT.getType(), ContractBusinessTypeEnum.SALE_PAPER_CONTRACT.getType());
    }

    private void addRoleCondition(LambdaQueryWrapper<ContractPo> lambdaQueryWrapper) {
        if (UserContextUtil.isRole(saleManagerRoleKey)) {
            lambdaQueryWrapper.eq(ContractPo::getSaleManagerId, UserContextUtil.getCurrentUserId());
        } else if (UserContextUtil.isRole(areaManagerRoleKey)) {
            lambdaQueryWrapper.in(ContractPo::getDeptId, UserContextUtil.getCurrentUser().getDeptIds());
            List<Long> userDeptIds = uaaFeignClientManager.getCurrentUserDeptIds();
            if (CollUtil.isNotEmpty(userDeptIds)) {
                lambdaQueryWrapper.in(ContractPo::getDeptId, userDeptIds);
            } else {
                log.warn("current user {} has no dept", UserContextUtil.getCurrentUserName());
                throw new HMYRuntimeException(502000016);
            }
        }
    }

    /**
     * 获取最新的授权人变更信息
     *
     * @param contractInfoResponse 合同信息
     */
    private void getLatestAuthorizerModify(ContractInfoResponse contractInfoResponse) {
        LambdaQueryWrapper<AuthorizerModifyPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AuthorizerModifyPo::getContractId, contractInfoResponse.getContractId());
        wrapper.eq(AuthorizerModifyPo::getIsDeleted, false);
        wrapper.orderByDesc(AuthorizerModifyPo::getCreateTime);
        List<AuthorizerModifyPo> authorizerModifyList = authorizerModifyMapper.selectList(wrapper);
        if (CollectionUtil.isNotEmpty(authorizerModifyList)) {
            AuthorizerModifyPo authorizerModify = authorizerModifyList.get(0);
            contractInfoResponse.setFileUrl(authorizerModify.getFileUrl());
            contractInfoResponse.setModifyReason(authorizerModify.getModifyReason());
        }
    }
}
